package cn.tang.tframe.springredis.mq.task;

import cn.tang.tframe.springredis.mq.processor.AbstractProcessor;
import cn.tang.tframe.springredis.mq.processor.Processors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.util.ArrayList;
import java.util.List;

public abstract class AbstractTask<T> implements Runnable {
	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	protected T data;

	@Override
	public void run() {
		T data = getData();
		logger.debug("start " + this.getClass() + " do task data={}", data);
		try {
			ApplicationContext context = getContext();
			if(null == context){
				logger.error("no springcontext for task {}",this.getClass());
				return;
			}
			processWork(data);
		} catch (Exception e) {
			logger.debug("end " + this.getClass() + " do task exception data={},error={}", data, e.getMessage());
			return;
		}
		logger.debug("end " + this.getClass() + " do task data={}", data);
	}

	public void processWork(T data) {
		List<Class<? extends AbstractProcessor>> processorList = getProcessor();
		for (Class<? extends AbstractProcessor> processorClass : processorList) {
			AbstractProcessor processor = null;
			try {
				processor = getContext().getBean(processorClass);
				logger.debug("start processor process : task={},processor={},data={},error={}", this.getClass(),
						processor.getClass(), data);
				processor.process(data);
				logger.debug("end processor process : task={},processor={},data={},error={}", this.getClass(),
						processor.getClass(), data );
			} catch (Exception e) {
				logger.error("end processor process error: task={},processor={},data={},error={}", this.getClass(),
						processor.getClass(), data, e.getMessage());
			}
		}
	}

	public T getData() {
		return this.data;
	}

	public void setData(T data) {
		this.data = data;
	}

	private List<Class<? extends AbstractProcessor>> getProcessor() {
		Processors processors = this.getClass().getAnnotation(Processors.class);
		Class[] classes = processors.value();
		List<Class<? extends AbstractProcessor>> taskList = new ArrayList<>();
		for (Class task : classes) {
			taskList.add(task);
		}
		return taskList;
	}
	abstract protected ApplicationContext getContext();

}
